import string

def merge(*vv):
    """Returns a Vector which is the max of the given vectors."""
    ret = Vector()
    for v in vv:
        ret.merge(v)
    return ret

def is_ver(ver):
    return isinstance(ver, tuple) and len(ver) == 2

def ver2str(ver):
    """Returns the string representation of the version tuple."""
    assert is_ver(ver)
    str = "%s:%s" % (ver[0], ver[1])
    return str

def str2ver(s):
    """Returns the tuple from the string."""
    l = s.split(':')
    if len(l) != 2:
        raise "Incorrectly formatted version string."
    return l[0], int(l[1])

def str2Vector(str):
    """Return the version.Vector that represented by the string."""
    if str == '':
        return Vector()
    else:
        return Vector(map(lambda v : str2ver(v), string.split(str, ' ')))

def from_raw(raw):
    return str2Vector(raw)
    
class Vector:
    """Classical version vector. Sorted in the order
    of the most recently updated to allow for truncation. Unlisted
    entries are treated as having value 0.

    XXX/bowei - handle truncation.
    """
    def __init__(self, vers = None):
        if vers is None:
            self.vers_ = []
        else:
            self.vers_ = vers

    def __str__(self):
        return self.to_str()

    def merge(self, other):
        """Takes the max of the version in other."""
        for v in other.vers_:
            if self[v[0]] < v[1]:
                self[v[0]] = v[1]

    def to_str(self):
        return string.join(map(lambda v: ver2str(v), self.vers_), ' ')
    
    def to_raw(self):
	return self.to_str()

    def cmp(a, b):
        """Compare two version vectors. Returns -2, -1, 0, 1 for
        incomparable, less, equal, greater."""
        if not isinstance(b, Vector):
            return -2

        lt = False
        gt = False

        for v in a.vers_:
            c = cmp(v[1], b[v[0]])
            if c == -1:
                lt = True
            elif c == 1:
                gt = True
        for v in b.vers_:
            c = cmp(a[v[0]], v[1])
            if c == -1:
                lt = True
            elif c == 1:
                gt = True
                
        if lt and gt:
            return -2
        elif lt:
            return -1
        elif gt:
            return 1
        else:
            return 0

    def __len__(self):
        return len(self.vers_)

    def __getitem__(self, id):
        for v in self.vers_:
            if v[0] == id:
                return v[1]
        return 0

    def __setitem__(self, id, ver):
        for v in self.vers_:
            if v[0] == id:
                self.vers_[self.vers_.index(v)] = (v[0], ver)
                return
        self.vers_.insert(0, (id, ver))
    
    def __lt__(self, other):
        c = self.cmp(other)
        return c == -1
        
    def __eq__(self, other):
        c = self.cmp(other)
        return c == 0
    
    def __ne__(self, other):
        c = self.cmp(other)
        return c == -2
    
    def __gt__(self, other):
        c = self.cmp(other)
        return c == 1
    
    def __le__(self, other):
        c = self.cmp(other)
        return c == -1 or c == 0
    
    def __ge__(self, other):
        c = self.cmp(other)
        return c == 1 or c == 0
